// 胎温胎压处理单元
package main

import (
	"errors"
	"fmt"
	"server/src/common"
	"server/src/protocol808"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"
	//"smartu365.com/protocol808"
)

// 处理单元
type Processor struct {
	dbo          *DBOperation
	cfg          *Config
	testSensorID string
	vehicleAxel  VehicleAxel
}

// 构造函数
func NewProcessor(dbo *DBOperation, cfg *Config) *Processor {
	p := Processor{dbo: dbo, cfg: cfg, testSensorID: cfg.TestSensorID}
	return &p
}

const (
	WarningFastLeak       int = 1 //急漏气
	WarningSlowLeak       int = 2 //慢漏气
	WarningTempretureHigh int = 3 //温度高
	WarningPressureHigh   int = 4 //气压高
	WarningPresureLow     int = 5 //气压低
	WarningSensorLost     int = 6 //发射器失联
	WarningVoltageLow     int = 7 //发射器电池电压低
)

const (
	WarningStatusInvalid   int = -1 //无效报警纪录，如重复报警
	WarningStatusNew       int = 0  //新纪录
	WarningStatusnNotified int = 1  //已通知
	WarningStatusDone      int = 2  //已处理
)

const DefaultPressureThresholdHigh float32 = 12.1
const DefaultPressureThresholdLow float32 = 6.9
const DefaultTemperatureThreshold int = 70

// 主执行函数
func (p *Processor) Run() {
	// 重置未更新的胎温胎压数据
	p.dbo.UpdateNewRawDatas()

	// 处理胎温胎压纪录类别 0900
	go TimerBirthWarmPress0900(p.dbo, p.cfg)

	//select {}
}

// 处理胎温胎压纪录类别 0900
func (p *Processor) processBirthWarmPress0900() {
	var rawDatas []RawDataT
	var err error

	zLog("处理胎温胎压纪录类别 0900 start time::", time.Now().Format(common.Layout))

	rawDatas, err = p.dbo.GetNewRawDatas()
	if err != nil {
		zLogError("读胎温胎压原始数据时出错：", err.Error())
		return
	}

	zLog("读到", len(rawDatas), "条新的胎温胎压数据")
	if len(rawDatas) > 0 {
		for _, v := range rawDatas {
			go p.dbo.UpdateLastRawData(v.ID)
		}

		for k, v := range rawDatas {
			zLog("start k::", k, " ID为::", v.ID.Hex(), "设备号::", v.Imei)
			p.processRoutine(k, &v)
			zLog("end k::", k, " ID为::", v.ID.Hex(), "设备号::", v.Imei)
		}
	}
}

func (p *Processor) processRoutine(k int, v *RawDataT) {
	if p.dbo.ReceiverStatus(v.Imei) != -2 {
		err := p.processOne(v)
		if err != nil {
			zLogError("处理第", k, "条数据，ID为 ", v.ID.Hex(), "，设备号为 ", v.Imei, "异常：", err.Error())
		}
	}
	p.dbo.RemoveLastRawData(v.ID)
}

func (p *Processor) processOne(data *RawDataT) error {
	defer func() {
		if err := recover(); err != nil {
			//设置原始数据的状态
			//p.dbo.SetRawDataStatus(data.ID, RawDataStatError, "Processor.processOne发生未知错误")
			fmt.Println(time.Now(), "Processor.processOne发生未知错误,ID:", data.ID.Hex(), ", data:", data.Data)
		}
	}()

	res := protocol808.Request{}
	err, header, body := res.Parse(data.Data)
	if err != nil {
		return err
	}
	if header.MessageType != protocol808.PTTirePresure {
		return errors.New("不是胎温胎压(0900)协议数据")
	}

	tp := protocol808.TirePressure{}
	tp.Set(body)

	tire := TireDataRawT{}
	tire._id = bson.NewObjectId()
	tire.RawId = data.ID
	tire.Rid = header.TerminalId
	tire.Date = tp.Date
	tire.Time = tp.Time
	tire.T = time.Now().Unix()
	tire.Latitude = tp.Latitude
	tire.Longitude = tp.Longitude
	tire.Count = tp.TireCount
	tire.Tires = tp.Datas

	//保存轮胎原始数据信息表
	dboErr := p.dbo.SaveTireRawData(&tire)
	if dboErr == nil {
		//保存胎温胎压数据
		p.dbo.SaveTireData(&tire)

		//检查是否有报警数据
		p.processWarning(&tire)
		if tire.Count == 1 {
			//如果轮位数等于1，则直接添加轮位，主要是为了测试和安装时候方便
			sid := tire.Tires[0].SensorId
			if sid != "" && !strings.Contains(p.testSensorID, sid) {
				p.dbo.SaveRelation(tire.Rid, tire.Tires[0].SensorId, tire.Tires[0].CardId, tire.Tires[0].SerialNum)
			}
		} else if tire.Count > 1 {
			//如果轮位数大于1，则更新轮位信息
			p.processTirePosition(&tire, true)
		}
	}

	return dboErr
}

// 设备的关联关系
type RidRelationT struct {
	ID     bson.ObjectId `bson:"_id"`
	Sid    string        `bson:"sid"`
	CardId int           `bson:"cardid"`
	SN     int           `bson:"sn"`
	KeepIt bool
}

type RidRelationsT struct {
	relations []RidRelationT
}

func (p *RidRelationsT) merge(newRelation *RidRelationsT) {
	var p1, p2 *RidRelationT

	//首先判断老的轮位是否在新的轮位中
	for i := 0; i < len(p.relations); i++ {
		p1 = &p.relations[i]
		p1.KeepIt = false
		for j := 0; j < len(newRelation.relations); j++ {
			p2 = &newRelation.relations[j]
			if !p2.KeepIt {
				if p1.CardId == p2.CardId && p1.SN == p2.SN {
					if p1.Sid == p2.Sid {
						p1.KeepIt = true
						p2.KeepIt = true
					} else {
						//更新关联库中的数据
						p1.ID = ""
						p1.Sid = p2.Sid
					}
					break
				}
			}
		}
	}
	//将新增加的轮位信息添加到老的数组中
	for i := 0; i < len(newRelation.relations); i++ {
		if !newRelation.relations[i].KeepIt {
			p.relations = append(p.relations, newRelation.relations[i])
		}
	}
}

// 处理轮位信息
func (p *Processor) processTirePosition(tireData *TireDataRawT, checkCount bool) {
	if checkCount && tireData.Count < 2 {
		return
	}

	newRrs := RidRelationsT{relations: make([]RidRelationT, 0)}
	for _, v := range tireData.Tires {
		if !strings.Contains(p.testSensorID, v.SensorId) && v.Learned == 0 {
			rr := RidRelationT{Sid: v.SensorId, CardId: v.CardId, SN: v.SerialNum}
			newRrs.relations = append(newRrs.relations, rr)
		}
	}
	oldRrs := p.dbo.getRelation(tireData.Rid)
	if oldRrs == nil {
		oldRrs = &newRrs
	} else {
		oldRrs.merge(&newRrs)
	}

	p.dbo.refreshTirePosition(tireData.Rid, oldRrs.relations)
}

// 处理报警数据
func (p *Processor) processWarning(tireData *TireDataRawT) {
	var warningType int
	var tw TireWarningT
	var err error

	tw.fromTireDataRaw(tireData)
	tw.Status = WarningStatusNew
	haveWarning := false

	var threshold *ReceiverThresholdT
	if len(tireData.Tires) > 0 {
		threshold, err = p.dbo.receiverThreshold(tireData.Rid)
		if err != nil || threshold == nil {
			threshold = &ReceiverThresholdT{}
		}
		if threshold.Threshold.Temperature == 0 {
			threshold.Threshold.Temperature = DefaultTemperatureThreshold
		}
		for i := 0; i < 5; i++ {
			if threshold.Threshold.Pressure[i][0] == 0.0 {
				threshold.Threshold.Pressure[i][0] = DefaultPressureThresholdHigh
			}
			if threshold.Threshold.Pressure[i][1] == 0.0 {
				threshold.Threshold.Pressure[i][1] = DefaultPressureThresholdLow
			}
		}
	}

	var maxPressure, minPressure float32
	for _, v := range tireData.Tires {
		if v.Learned == 1 {
			continue
		}
		tw.fromTireData(&v)
		if v.Temperature == 205 || v.Presure == 0.0 {
			if v.NoData == 1 {
				tw.WarningType = WarningSensorLost
				p.dbo.SaveWarningInfor(&tw)
			}
			//无效数据，不报警
			continue
		}

		//检查气压状态
		warningType = 0
		if v.PresureStatus == 1 {
			warningType = WarningFastLeak
		}

		if warningType != 0 {
			tw.WarningType = warningType
			//保存漏气报警信息
			p.dbo.SaveWarningInfor(&tw)
		} else {
			p.dbo.LastWarningRestore(&tw, WarningFastLeak, WarningSlowLeak)
		}

		//检查气压
		warningType = 0
		maxPressure, minPressure = p.getPressureThreshold(threshold.Threshold.Pressure, threshold.Type,
			v.CardId, v.SerialNum)
		if v.Presure > maxPressure {
			warningType = WarningPressureHigh
		} else if v.Presure < minPressure {
			warningType = WarningPresureLow
		}
		if warningType != 0 {
			tw.WarningType = warningType
			haveWarning = true
			p.dbo.SaveWarningInfor(&tw)
		} else {
			p.dbo.LastWarningRestore(&tw, WarningPressureHigh, WarningPresureLow)
		}

		//检查传感器电压
		if v.VoltageStatus == 1 {
			tw.WarningType = WarningVoltageLow
			haveWarning = true
			p.dbo.SaveWarningInfor(&tw)
		} else {
			p.dbo.LastWarningRestore(&tw, WarningVoltageLow)
		}

		//传感器失联
		if v.NoData == 1 {
			tw.WarningType = WarningSensorLost
			p.dbo.SaveWarningInfor(&tw)
		} else {
			p.dbo.LastWarningRestore(&tw, WarningSensorLost)
		}
	}

	//判断是否有高温、高压、低压，用于统计异常工作时间
	p.dbo.dealWarningTime(tw.Rid, tw.Date, tw.Time, haveWarning)
}

func (p *Processor) getPressureThreshold(thresholds [5][2]float32, vehicleType, cardid, sn int) (max float32, min float32) {
	axel := p.vehicleAxel.Axel(vehicleType, cardid, sn)
	if axel < 0 || axel >= 5 {
		max, min = DefaultPressureThresholdHigh, DefaultPressureThresholdLow
	} else {
		max, min = thresholds[axel][0], thresholds[axel][1]
	}

	return
}
